package com.intelligent.ispc.core.repository.mongo.impl;

import com.intelligent.ispc.common.mapper.JsonMapper;
import com.intelligent.ispc.common.utils.StringUtils;
import com.intelligent.ispc.core.dto.AnalysisKeyResultDto;
import com.intelligent.ispc.core.dto.StationDto;
import com.intelligent.ispc.core.entity.*;
import com.intelligent.ispc.core.repository.mongo.GRRTestDataDao;
import com.intelligent.ispc.utils.Constant;
import com.intelligent.ispc.utils.SystemConfig;
import com.mongodb.AggregationOutput;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import java.util.*;
import java.util.regex.Pattern;

/**
 * Created by julia on 16/3/10.
 */
@Repository
public class GRRTestDataDaoImpl implements GRRTestDataDao {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private SystemConfig systemConfig;

    protected JsonMapper mapper = JsonMapper.nonDefaultMapper();

    @Override
    public GRRTestData findGRRTestData(Map<String, Object> searchParams) {
        Query query = setQuery(searchParams);
        return mongoTemplate.findOne(query, GRRTestData.class, Constant.MONGODB_GRR_COLLECTION + searchParams.get("projectId"));
    }

    @Override
    public List<GRRTestData> findGRRTestDatas(Map<String, Object> searchParams) {

        Query query = setQuery(searchParams);
        return mongoTemplate.find(query, GRRTestData.class, Constant.MONGODB_GRR_COLLECTION + searchParams.get("projectId"));
    }

    @Override
    public List<GRRTestData> findGRRTestDatas(Map<String, Object> searchParams, Pageable pageable) {
        Query query = setQuery(searchParams);

        if (pageable != null) {
            query.with(pageable);
        }

        return mongoTemplate.find(query, GRRTestData.class, Constant.MONGODB_GRR_COLLECTION + searchParams.get("projectId"));
    }

    @Override
    @Deprecated
    public List<String> findDistinctGRRTestDatas(Map<String, Object> searchParams, String targeFiled) {
        Query query = filterItemsAndDutAttributeOfReturn(searchParams);
        List<String> results = mongoTemplate.getCollection(Constant.MONGODB_GRR_COLLECTION + searchParams.get("projectId")).distinct(targeFiled, query.getQueryObject());
        return results;
    }

    @Override
    public void updateGRRTestDatas(Map<String, Object> searchParams, Map<String, Object> updateParams) {
        Query query = filterItemsAndDutAttributeOfReturn(searchParams);

        Update update = new Update();
        for (Map.Entry<String, Object> entry : updateParams.entrySet()) {
            String key = entry.getKey();
            if (StringUtils.isNotBlank(key)) {
                update.set(key, entry.getValue());

            }
        }
        mongoTemplate.updateMulti(query, update, GRRTestData.class, Constant.MONGODB_GRR_COLLECTION + searchParams.get("projectId"));
    }

    @Override
    public void findAllAndRemove(Map<String, Object> searchParams) {
        Query query = filterItemsAndDutAttributeOfReturn(searchParams);
        mongoTemplate.findAllAndRemove(query, GRRTestData.class, Constant.MONGODB_GRR_COLLECTION + searchParams.get("projectId"));
    }

    private Query setQuery(Map<String, Object> searchParams) {

        DateTimeFormatter format = DateTimeFormat.forPattern(systemConfig.getDateFormat());
        Query query = new Query();
        Criteria criteria = new Criteria();

        if (searchParams.containsKey("grrName")) {
            criteria.and("grrName").is(searchParams.get("grrName"));
        }

        if (searchParams.containsKey("id")) {
            ObjectId id = new ObjectId(searchParams.get("id").toString());
            criteria.and("_id").is(id);
        }

        if (searchParams.containsKey("serialNumber")) {
            Pattern pattern = Pattern.compile("^.*?" + searchParams.get("serialNumber") + ".*?$", Pattern.CASE_INSENSITIVE);
            criteria.and("testData.serialNumber").regex(pattern);
        }

        if (searchParams.containsKey("startTime") && !searchParams.containsKey("stopTime")) {
            criteria.and("grrStartTime").gte(DateTime.parse(searchParams.get("startTime").toString(), format).toDate());
        } else if (searchParams.containsKey("startTime") && searchParams.containsKey("stopTime")) {
            criteria.and("grrStartTime").gte(DateTime.parse(searchParams.get("startTime").toString(), format).toDate());
            criteria.and("grrEndTime").lte(DateTime.parse(searchParams.get("stopTime").toString(), format).toDate());
        } else if (!searchParams.containsKey("startTime") && searchParams.containsKey("stopTime")) {
            criteria.and("grrEndTime").lte(DateTime.parse(searchParams.get("stopTime").toString(), format).toDate());
        }

        if (searchParams.containsKey("isPass")) {
            criteria.and("testData.isPass").is(searchParams.get("isPass"));
        }

        if (searchParams.containsKey("isDelete")) {
            criteria.and("isDelete").is(searchParams.get("isDelete"));
        } else {
            criteria.and("isDelete").is(false);
        }

        query.with(new Sort(Sort.Direction.ASC, "testData.startTime"));

        if (searchParams.containsKey("isNeedItems") && !(boolean) searchParams.get("isNeedItems")) {
            query.fields().exclude("testItems");
        }

        if (searchParams.containsKey("isNeedDutAttributes") && !(boolean) searchParams.get("isNeedDutAttributes")) {
            query.fields().exclude("dutAttributes");
        }

        Criteria[] criterias = null;
        if (searchParams.containsKey("stationIdOrSlotNo")) {
            List<StationDto> stationDtoList = mapper.fromJson((String) searchParams.get("stationIdOrSlotNo"), mapper.contructCollectionType(List.class, StationDto.class));
            if (stationDtoList != null && !stationDtoList.isEmpty()) {
                criterias = new Criteria[stationDtoList.size()];
                for (int i = 0; i < stationDtoList.size(); i++) {
                    Criteria criteria1 = new Criteria();
                    if (StringUtils.isNotBlank(stationDtoList.get(i).getStationId()) || stationDtoList.get(i).getStationId() == "") {
                        criteria1.and("testData.stationId").is(stationDtoList.get(i).getStationId());
                    }
                    if (stationDtoList.get(i).getSlotNos() != null && !stationDtoList.get(i).getSlotNos().isEmpty()) {
                        criteria1.and("testData.slotNo").in(stationDtoList.get(i).getSlotNos());
                    }
                    criterias[i] = criteria1;
                }
            }
         }
        Criteria[] criterias1 = null;
        if (searchParams.containsKey(Constant.GRR_ANALYSIS_KEYS)) {
            List<AnalysisKeyResultDto> analysisKeyResultDtoList = mapper.fromJson((String) searchParams.get(Constant.GRR_ANALYSIS_KEYS), mapper.contructCollectionType(List.class, AnalysisKeyResultDto.class));
            if (analysisKeyResultDtoList != null && !analysisKeyResultDtoList.isEmpty()) {
                criterias1 = new Criteria[analysisKeyResultDtoList.size()];
                for (int i = 0; i < analysisKeyResultDtoList.size(); i++) {
                    Criteria criteria1 = new Criteria();
                    String groupKey = analysisKeyResultDtoList.get(i).getGroupKey();
                    if (StringUtils.isNotBlank(groupKey) || groupKey == "") {
                        if (groupKey.contains(Constant.GLOBAL_SEPARATOR)) {
                            String[] groupKeys = groupKey.split(Constant.GLOBAL_SEPARATOR);
                            if (analysisKeyResultDtoList.get(i).isGroup1KeyFlag()) {
                                if (groupKeys[0] != "") {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup1Key()).is(groupKeys[0]);
                                } else {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup1Key()).exists(false);
                                }
                            } else {
                                criteria1.and("dutAttributes.attributeName").is(analysisKeyResultDtoList.get(i).getGroup1Key());
                                if (groupKeys[0] != "") {
                                    criteria1.and("dutAttributes.attributeValue").is(groupKeys[0]);
                                } else {
                                    criteria1.and("dutAttributes.attributeValue").exists(false);
                                }
                            }

                            if (analysisKeyResultDtoList.get(i).isGroup2KeyFlag()) {
                                if (groupKeys[1] != "") {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup2Key()).is(groupKeys[1]);
                                } else {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup2Key()).exists(false);
                                }
                            } else {
                                criteria1.and("dutAttributes.attributeName").is(analysisKeyResultDtoList.get(i).getGroup2Key());
                                if (groupKeys[1] != "") {
                                    criteria1.and("dutAttributes.attributeValue").is(groupKeys[1]);
                                } else {
                                    criteria1.and("dutAttributes.attributeValue").exists(false);
                                }
                            }
                        } else {
                            if (analysisKeyResultDtoList.get(i).isGroup1KeyFlag()) {
                                if (groupKey != "") {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup1Key()).is(groupKey);
                                } else {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup1Key()).exists(false);
                                }
                            } else {
                                criteria1.and("dutAttributes.attributeName").is(analysisKeyResultDtoList.get(i).getGroup1Key());
                                if (groupKey != "") {
                                    criteria1.and("dutAttributes.attributeValue").is(groupKey);
                                } else {
                                    criteria1.and("dutAttributes.attributeValue").exists(false);
                                }

                            }
                        }
                    }
                    if (analysisKeyResultDtoList.get(i).getDimensionList() != null && !analysisKeyResultDtoList.get(i).getDimensionList().isEmpty()) {
                        String dimension = analysisKeyResultDtoList.get(i).getDimensionKey();
                        if (analysisKeyResultDtoList.get(i).isDimensionKeyFlag()) {
                            if (analysisKeyResultDtoList.get(i).getDimensionList().size() == 1 && "".equals(analysisKeyResultDtoList.get(i).getDimensionList().get(0))) {
                                criteria1.and(dimension).exists(false);
                            } else {
                                criteria1.and(dimension).in(analysisKeyResultDtoList.get(i).getDimensionList());
                            }
                        } else {
                            criteria1.and("dutAttributes.attributeName").is(dimension);
                            if (analysisKeyResultDtoList.get(i).getDimensionList().size() == 1 && "".equals(analysisKeyResultDtoList.get(i).getDimensionList().get(0))) {
                                criteria1.and("dutAttributes.attributeValue").exists(false);
                            } else {
                                criteria1.and("dutAttributes.attributeValue").in(analysisKeyResultDtoList.get(i).getDimensionList());
                            }
                        }
                    }
                    criterias1[i] = criteria1;
                }
            }
        }

        if (criterias == null) {
            if (criterias1 != null) {
                query.addCriteria(criteria.orOperator(criterias1));
            } else {
                query.addCriteria(criteria);
            }
        } else
            query.addCriteria(criteria.orOperator(criterias));

        return  query;
    }

    private Query filterItemsAndDutAttributeOfReturn(Map<String, Object> searchParams) {

        DateTimeFormatter format = DateTimeFormat.forPattern(systemConfig.getDateFormat());
        Query query = new Query();
        Criteria criteria = new Criteria();

        if (searchParams.containsKey("grrName")) {
            criteria.and("grrName").is(searchParams.get("grrName"));
        }

        if (searchParams.containsKey("id")) {
            ObjectId id = new ObjectId(searchParams.get("id").toString());
            criteria.and("_id").is(id);
        }

        if (searchParams.containsKey("serialNumber")) {
            Pattern pattern = Pattern.compile("^.*?" + searchParams.get("serialNumber") + ".*?$", Pattern.CASE_INSENSITIVE);
            criteria.and("testData.serialNumber").regex(pattern);
        }

        if (searchParams.containsKey("startTime") && !searchParams.containsKey("stopTime")) {
            criteria.and("grrStartTime").gte(DateTime.parse(searchParams.get("startTime").toString(), format).toDate());
        } else if (searchParams.containsKey("startTime") && searchParams.containsKey("stopTime")) {
            criteria.and("grrStartTime").gte(DateTime.parse(searchParams.get("startTime").toString(), format).toDate());
            criteria.and("grrEndTime").lte(DateTime.parse(searchParams.get("stopTime").toString(), format).toDate());
        } else if (!searchParams.containsKey("startTime") && searchParams.containsKey("stopTime")) {
            criteria.and("grrEndTime").lte(DateTime.parse(searchParams.get("stopTime").toString(), format).toDate());
        }

        if (searchParams.containsKey("isPass")) {
            criteria.and("testData.isPass").is(searchParams.get("isPass"));
        }

        if (searchParams.containsKey("isDelete")) {
            criteria.and("isDelete").is(searchParams.get("isDelete"));
        } else {
            criteria.and("isDelete").is(false);
        }

        query.with(new Sort(Sort.Direction.ASC, "testData.startTime"));

        query.fields().exclude("testItems");
        query.fields().exclude("dutAttributes");

        Criteria[] criterias = null;
        if (searchParams.containsKey("stationIdOrSlotNo")) {
            List<StationDto> stationDtoList = mapper.fromJson((String) searchParams.get("stationIdOrSlotNo"), mapper.contructCollectionType(List.class, StationDto.class));
            if (stationDtoList != null && !stationDtoList.isEmpty()) {
                criterias = new Criteria[stationDtoList.size()];
                for (int i = 0; i < stationDtoList.size(); i++) {
                    Criteria criteria1 = new Criteria();
                    if (StringUtils.isNotBlank(stationDtoList.get(i).getStationId()) || stationDtoList.get(i).getStationId() == "") {
                        criteria1.and("testData.stationId").is(stationDtoList.get(i).getStationId());
                    }
                    if (stationDtoList.get(i).getSlotNos() != null && !stationDtoList.get(i).getSlotNos().isEmpty()) {
                        criteria1.and("testData.slotNo").in(stationDtoList.get(i).getSlotNos());
                    }
                    criterias[i] = criteria1;
                }
            }
        }

        Criteria[] criterias1 = null;
        if (searchParams.containsKey(Constant.GRR_ANALYSIS_KEYS)) {
            List<AnalysisKeyResultDto> analysisKeyResultDtoList = mapper.fromJson((String) searchParams.get(Constant.GRR_ANALYSIS_KEYS), mapper.contructCollectionType(List.class, AnalysisKeyResultDto.class));
            if (analysisKeyResultDtoList != null && !analysisKeyResultDtoList.isEmpty()) {
                criterias1 = new Criteria[analysisKeyResultDtoList.size()];
                for (int i = 0; i < analysisKeyResultDtoList.size(); i++) {
                    Criteria criteria1 = new Criteria();
                    String groupKey = analysisKeyResultDtoList.get(i).getGroupKey();
                    if (StringUtils.isNotBlank(groupKey) || groupKey == "") {
                        if (groupKey.contains(Constant.GLOBAL_SEPARATOR)) {
                            String[] groupKeys = groupKey.split(Constant.GLOBAL_SEPARATOR);
                            if (analysisKeyResultDtoList.get(i).isGroup1KeyFlag()) {
                                if (groupKeys[0] != "") {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup1Key()).is(groupKeys[0]);
                                } else {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup1Key()).exists(false);
                                }
                            } else {
                                criteria1.and("dutAttributes.attributeName").is(analysisKeyResultDtoList.get(i).getGroup1Key());
                                if (groupKeys[0] != "") {
                                    criteria1.and("dutAttributes.attributeValue").is(groupKeys[0]);
                                } else {
                                    criteria1.and("dutAttributes.attributeValue").exists(false);
                                }
                            }

                            if (analysisKeyResultDtoList.get(i).isGroup2KeyFlag()) {
                                if (groupKeys[1] != "") {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup2Key()).is(groupKeys[1]);
                                } else {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup2Key()).exists(false);
                                }
                            } else {
                                criteria1.and("dutAttributes.attributeName").is(analysisKeyResultDtoList.get(i).getGroup2Key());
                                if (groupKeys[1] != "") {
                                    criteria1.and("dutAttributes.attributeValue").is(groupKeys[1]);
                                } else {
                                    criteria1.and("dutAttributes.attributeValue").exists(false);
                                }
                            }
                        } else {
                            if (analysisKeyResultDtoList.get(i).isGroup1KeyFlag()) {
                                if (groupKey != "") {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup1Key()).is(groupKey);
                                } else {
                                    criteria1.and(analysisKeyResultDtoList.get(i).getGroup1Key()).exists(false);
                                }
                            } else {
                                criteria1.and("dutAttributes.attributeName").is(analysisKeyResultDtoList.get(i).getGroup1Key());
                                if (groupKey != "") {
                                    criteria1.and("dutAttributes.attributeValue").is(groupKey);
                                } else {
                                    criteria1.and("dutAttributes.attributeValue").exists(false);
                                }

                            }
                        }
                    }
                    if (analysisKeyResultDtoList.get(i).getDimensionList() != null && !analysisKeyResultDtoList.get(i).getDimensionList().isEmpty()) {
                        String dimension = analysisKeyResultDtoList.get(i).getDimensionKey();
                        if (analysisKeyResultDtoList.get(i).isDimensionKeyFlag()) {
                            if (analysisKeyResultDtoList.get(i).getDimensionList().size() == 1 && "".equals(analysisKeyResultDtoList.get(i).getDimensionList().get(0))) {
                                criteria1.and(dimension).exists(false);
                            } else {
                                criteria1.and(dimension).in(analysisKeyResultDtoList.get(i).getDimensionList());
                            }
                        } else {
                            criteria1.and("dutAttributes.attributeName").is(dimension);
                            if (analysisKeyResultDtoList.get(i).getDimensionList().size() == 1 && "".equals(analysisKeyResultDtoList.get(i).getDimensionList().get(0))) {
                                criteria1.and("dutAttributes.attributeValue").exists(false);
                            } else {
                                criteria1.and("dutAttributes.attributeValue").in(analysisKeyResultDtoList.get(i).getDimensionList());
                            }
                        }
                    }
                    criterias1[i] = criteria1;
                }
            }
        }

        if (criterias == null) {
            if (criterias1 != null) {
                query.addCriteria(criteria.orOperator(criterias1));
            } else {
                query.addCriteria(criteria);
            }
        } else
            query.addCriteria(criteria.orOperator(criterias));

        return  query;
    }
}
